package com.corpgovernment.permission.service;

import com.corpgovernment.api.permission.vo.GetUserPermissionListRequest;
import com.corpgovernment.common.base.BaseUserInfo;
import com.corpgovernment.common.handler.ICacheHandler;
import com.corpgovernment.common.utils.BaseUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.corpgovernment.organization.util.JsonUtil;
import com.corpgovernment.organization.util.StrUtils;
import com.corpgovernment.permission.entity.MbAuthorityConfigContent;
import com.corpgovernment.permission.entity.MbPermissionDto;
import com.corpgovernment.permission.entity.db.MbAuthorityConfig;
import com.corpgovernment.permission.entity.db.MbPermission;
import com.corpgovernment.permission.mapper.ISqlMapper;
import com.corpgovernment.permission.mapper.MbAuthorityConfigMapper;
import com.corpgovernment.permission.mapper.PermissionMapper;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.BooleanUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wangyujue
 */
@Service
@Slf4j
public class PermissionService {

    /**
     * 越权hashmap缓存键
     */
    private final static String Beyond_Authority_Hash_Key = "Beyond_Authority_Hash_Key";

    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private MbAuthorityConfigMapper authorityConfigMapper;
    @Autowired
    private UserService userService;
    @Autowired
    private ISqlMapper sqlMapper;
    @Autowired
    private ICacheHandler cacheHandler;



    public List<MbPermission> findPermById(List<Long> id) {
        Example example = new Example(MbPermission.class);
        example.createCriteria().andIn("id", id);
        return Optional.ofNullable(permissionMapper.selectByExample(example)).orElse(new ArrayList<>());
    }


    /**
     * 获取全部权限模块
     */
    public List<MbPermissionDto> getAllPermissionList(Boolean isBackground, BaseUserInfo userInfo) {
        Example example = new Example(MbPermission.class);
        Example.Criteria criteria = example.createCriteria()
                .andEqualTo("isDeleted", false)
                .andEqualTo("isParentMenu", false);
        //后端可以查询全部权限
        if (BooleanUtils.isNotTrue(isBackground)) {
            criteria.andIn("scene", Arrays.asList("F", "N"));
        } else {
            criteria.andIn("scene", Arrays.asList("B", "N"));
        }
        example.orderBy("sort");

        List<MbPermission> list = BaseUtils.defaultList(permissionMapper.selectByExample(example));
        //根据当前用户过去可配置权限模块
        if (userInfo != null) {
            List<String> hasPermissionList = BaseUtils.defaultList(userService.getUserPermissionUrlList(new GetUserPermissionListRequest(userInfo.getUid(), userInfo.getOrgId())));
            // 后台用户，分配前台权限时，增加仅前台用户场景的权限
            if (userInfo.getBgUser() && BooleanUtils.isNotTrue(isBackground)) {
                list = list.stream().filter(x ->
                        hasPermissionList.contains(x.getResKey()) || StringUtils.equalsIgnoreCase(x.getScene(), "F"))
                        .collect(Collectors.toList());
            } else {
                list = list.stream().filter(x -> hasPermissionList.contains(x.getResKey())).collect(Collectors.toList());
            }
        }

        // 同属性list互转，无换行必要了吧
        return list.stream()
                .map(p -> {
                    MbPermissionDto mp = MbPermissionDto.builder().build();
                    BeanUtils.copyProperties(p, mp);
                    return mp;
                })
                .collect(Collectors.toList());
    }


    /**
     * 检查是否越权
     *
     * @param userInfo
     * @param data
     * @param url
     * @param source
     * @return
     */
    public Boolean checkBeyondAuthority(BaseUserInfo userInfo, Map<String, Object> data, String url, String source) {
        // 默认通过
        Boolean result = Boolean.TRUE;
        try {
            // 参数校验
            if (userInfo == null || StringUtils.isBlank(userInfo.getUid())
                    || data == null
                    || StringUtils.isBlank(url)
                    || StringUtils.isBlank(source) || !StrUtils.In(source, "APP", "PCBOOK")) {
                return result;
            }

            // 从缓存中读取配置
            if (!cacheHandler.hasKey(Beyond_Authority_Hash_Key)) {
                MbAuthorityConfig selectParam = new MbAuthorityConfig();
                selectParam.setIs_deleted(false);
                List<MbAuthorityConfig> configs = Optional.ofNullable(authorityConfigMapper.select(selectParam)).orElse(new ArrayList<>());
                Map<String, MbAuthorityConfig> map = configs.stream().collect(Collectors.toMap(
                        c -> c.getUrl().toUpperCase(), c -> c, (c1, c2) -> c2
                ));
                cacheHandler.setHash(Beyond_Authority_Hash_Key, map, 3600);
            }
            MbAuthorityConfig config = (MbAuthorityConfig) cacheHandler.getHashValue(Beyond_Authority_Hash_Key, url.toUpperCase());
            log.info("config 的值：{}", config);
            if (config == null || StringUtils.isBlank(config.getSqlText())) {
                return result;
            }
            MbAuthorityConfigContent content = JsonUtil.toObject(config.getSqlText(), MbAuthorityConfigContent.class);
            if (content == null || StringUtils.isBlank(content.getSql())) {
                return result;
            }

            // 结合参数，拿到sql
            List<String> paramNames = Optional.ofNullable(content.getParams()).orElse(new ArrayList<>());
            List<Object> objs = new ArrayList<>();
            for (String name : paramNames) {
                // loginUid 使用baseUserInfo里的uid
                Object value = null;
                if ("loginUidOfBaseUserInfo".equalsIgnoreCase(name)) {
                    value = userInfo.getUid();
                } else {
                    value = getParamValue(data, name);
                }
                if (value == null) {
                    objs.add(" is null ");
                } else if (value instanceof List) {
                    List<String> list = new ArrayList<>();
                    for (Object o : (List) value) {
                        if (o != null && StrUtils.checkSqlParam(o.toString())) {
                            return false;
                        }
                        list.add(o == null ? "''" : " '" + o.toString() + "' ");
                    }
                    objs.add(String.join(",", list));
                } else if (value.getClass().isArray()) {
                    List<String> list = new ArrayList<>();
                    for (Object o : (Object[]) value) {
                        if (o != null && StrUtils.checkSqlParam(o.toString())) {
                            return false;
                        }
                        list.add(o == null ? "''" : " '" + o.toString() + "' ");
                    }
                    objs.add(String.join(",", list));
                } else if (StrUtils.checkSqlParam(value.toString())) {
                    return false;
                } else {
                    objs.add(" '" + value + "' ");
                }
            }
            String sql = String.format(content.getSql(), objs.toArray());
            log.info("sqltext：{}，beyondAuthoritySql：{}", config.getSqlText(), sql);
            String sqlValue = sqlMapper.selectOne(sql);
            return "1".equalsIgnoreCase(sqlValue);
        } catch (Exception e) {
            log.error("checkBeyondAuthority 失败：{}", e);
        }
        return result;
    }

    /**
     * 递归查找参数值
     *
     * @param data
     * @param name abc.edfg.hijkl
     * @return
     */
    private Object getParamValue(Map<String, Object> data, String name) {
        if (StringUtils.isBlank(name)) {
            return null;
        }
        if (!name.contains(".")) {
            return data.get(name);
        }

        Object obj = data.get(name.substring(0, name.indexOf(".")));
        String newName = name.substring(name.indexOf(".") + 1);
        if (obj == null || StringUtils.isBlank(newName)) {
            return null;
        }
        Map<String, Object> subData = (Map<String, Object>) obj;
        if (CollectionUtils.isEmpty(subData)) {
            return null;
        }
        return getParamValue(subData, newName);
    }

    /**
     * 清楚越权缓存
     *
     * @return
     */
    public Boolean clearBeyondAuthorityCache() {
        return cacheHandler.delete("Beyond_Authority_Hash_Key");
    }
}
